﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataTransferObjects;
using System.IO;
using BasicEncrypt_DecryptFiles.Code;
using System.Security.Cryptography;

namespace Business
{
    public class EncryptDecryptBUS
    {
        private SymmetricAlgorithm mCryptoService;
        private byte[] dummyByte = new byte[] {0x49, 0x76, 0x61, 0x6e, 0x20, 0x4d, 
            0x65, 0x64, 0x76, 0x65, 0x64, 0x65, 0x76};


        private bool isCompability(AlgProvider iAlg, ModeProvider iMode, PaddingProvider iPadding)
        {
            switch (iAlg)
            {
                case AlgProvider.DES:
                case AlgProvider.Rijndael:
                case AlgProvider.RC2:
                    if (iMode == ModeProvider.OFB || iMode == ModeProvider.CTS)
                        return false;
                    break;
            }
            return true;
        }

        private bool postProcessing(string strPassPost, string IV, int iAlgorithm, int iModes, int iPaddingMode)
        {
            AlgProvider iAlg = new AlgProvider();
            ModeProvider iMode = new ModeProvider();
            PaddingProvider iPadding = new PaddingProvider();

            switch (iAlgorithm)
            {
                case 0:
                    iAlg = AlgProvider.Rijndael;
                    break;
                case 1:
                    iAlg = AlgProvider.RC2;
                    break;
                case 2:
                    iAlg = AlgProvider.DES;
                    break;
                case 3:
                    iAlg = AlgProvider.TripleDES;
                    break;
                //default:
                //    iAlg = AlgProvider.RC2;
                //break;
            }

            switch (iModes)
            {
                case 0:
                    iMode = ModeProvider.ECB;
                    break;
                case 1:
                    iMode = ModeProvider.CBC;
                    break;
                case 2:
                    iMode = ModeProvider.CFB;
                    break;
                case 3:
                    iMode = ModeProvider.OFB;
                    break;
                case 4:
                    iMode = ModeProvider.CTS;
                    break;
            }

            switch (iPaddingMode)
            {
                case 0:
                    iPadding = PaddingProvider.X923;
                    break;
                case 1:
                    iPadding = PaddingProvider.PKCS7;
                    break;
                case 2:
                    iPadding = PaddingProvider.ISO10126;
                    break;
            }

            if (!isCompability(iAlg, iMode, iPadding))
                return false;

            initAlg(iAlg, strPassPost, IV, iMode, iPadding);

            return true;
        }

        private void initAlg(AlgProvider iAlg, String strPassword, String IV,
            ModeProvider iMode, PaddingProvider iPadding)
        {            
            PasswordDeriveBytes pdbPass = new PasswordDeriveBytes(strPassword, dummyByte);
            PasswordDeriveBytes pdbIV = new PasswordDeriveBytes(IV, dummyByte);

            switch (iAlg)
            {
                case AlgProvider.Rijndael:
                    mCryptoService = new RijndaelManaged();
                    mCryptoService.Key = pdbPass.GetBytes(16);
                    mCryptoService.IV = pdbIV.GetBytes(16);
                    break;
                case AlgProvider.DES:
                    mCryptoService = new DESCryptoServiceProvider();
                    mCryptoService.Key = pdbPass.GetBytes(8);
                    mCryptoService.IV = pdbIV.GetBytes(8);
                    break;
                case AlgProvider.RC2:
                    mCryptoService = new RC2CryptoServiceProvider();
                    mCryptoService.Key = pdbPass.GetBytes(8);
                    mCryptoService.IV = pdbIV.GetBytes(8);
                    break;
                case AlgProvider.TripleDES:
                    mCryptoService = new TripleDESCryptoServiceProvider();
                    mCryptoService.Key = pdbPass.GetBytes(21);
                    mCryptoService.IV = pdbIV.GetBytes(8);
                    break;
            }
            switch (iMode)
            {
                case ModeProvider.ECB:
                    mCryptoService.Mode = CipherMode.ECB;
                    break;
                case ModeProvider.CFB:
                    mCryptoService.Mode = CipherMode.ECB;
                    break;
                case ModeProvider.CBC:
                    mCryptoService.Mode = CipherMode.ECB;
                    break;
                case ModeProvider.OFB:
                    mCryptoService.Mode = CipherMode.ECB;
                    break;
                case ModeProvider.CTS:
                    mCryptoService.Mode = CipherMode.ECB;
                    break;
            }

            switch (iPadding)
            {
                case PaddingProvider.ISO10126:
                    mCryptoService.Padding = PaddingMode.ISO10126;
                    break;
                case PaddingProvider.PKCS7:
                    mCryptoService.Padding = PaddingMode.PKCS7;
                    break;
                case PaddingProvider.X923:
                    mCryptoService.Padding = PaddingMode.ANSIX923;
                    break;
            }
        }

        public int encryptFile(int iUserID, string strEmailReceiver, int iAlgorithm, int iModes, int iPaddingMode, 
                                    String strFileIn, String strFileout)
        {
            //create pass from accountInfor
            AccountInforDTO accountInfor = AccountBUS.getAccInforFromDB(iUserID);
            string strPassPost = accountInfor.email + strEmailReceiver;
            string IV = strEmailReceiver;

            if (!postProcessing(strPassPost, IV, iAlgorithm, iModes, iPaddingMode))
            {
                return 1;
            }
            

            FileStream fsIn = new FileStream(strFileIn,
            FileMode.Open, FileAccess.Read);
  
            if (!fsIn.CanRead)
                return 2;

            
            ICryptoTransform encryptor = mCryptoService.CreateEncryptor();

            byte[] passEncryptByPubKey = rsaBUS.encryptUsePubKey(strEmailReceiver, mCryptoService.Key);
            byte[] data = new byte[fsIn.Length];
            fsIn.Read(data, 0, data.Length);
            
            byte[] dataEncrypted = encryptor.TransformFinalBlock(data, 0, (int) fsIn.Length);

            BinaryWriter binaryWriter = new BinaryWriter(new FileStream(strFileout, FileMode.CreateNew));
            binaryWriter.Write(iAlgorithm);
            binaryWriter.Write(iModes);
            binaryWriter.Write(iPaddingMode);
            binaryWriter.Write(passEncryptByPubKey.Length);
            binaryWriter.Write(passEncryptByPubKey);
            binaryWriter.Write(dataEncrypted.Length);
            binaryWriter.Write(dataEncrypted);

            fsIn.Close();
            binaryWriter.Close();
            return 3;
        }

        public int decryptFile(int iUserID, String strFileIn, String strFileout)
        {            
            BinaryReader binaryRead = new BinaryReader(new FileStream(strFileout, FileMode.Open));
            int iAlgorithm = binaryRead.ReadInt32();
            int iModes = binaryRead.ReadInt32();
            int iPaddingMode = binaryRead.ReadInt32();
            int passLength = binaryRead.ReadInt32();
            byte[] passEncryptByPubKey = binaryRead.ReadBytes(passLength);
            int dataEncryptedLength = binaryRead.ReadInt32();
            byte[] dataEncrypted = binaryRead.ReadBytes(dataEncryptedLength);

            byte[] strPassPost = rsaBUS.decryptUsePrivKey(iUserID, passEncryptByPubKey);

            //create pass from accountInfor
            AccountInforDTO accountInfor = AccountBUS.getAccInforFromDB(iUserID);
            string IV = accountInfor.email;

            if (!postProcessing(IV, IV, iAlgorithm, iModes, iPaddingMode))
            {
                return 1;
            }

            mCryptoService.Key = strPassPost;

            ICryptoTransform decryptor = mCryptoService.CreateDecryptor();

            byte[] dataDecrypted = decryptor.TransformFinalBlock(dataEncrypted, 0, dataEncrypted.Length);
            FileStream fsOut = new FileStream(strFileout, FileMode.CreateNew);
            fsOut.Write(dataDecrypted, 0, dataDecrypted.Length);

            fsOut.Close();
            binaryRead.Close();
            return 3;
        }
    }
}
